/**********************************************************************
* Filename: Jogador.java
* Created: 2012/04/30
* @author Fernando Brito e Abreu
**********************************************************************/
package pt.iscteiul.worldfootball.businesslayer;

import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;

import com.projectpoint.annotationnotfinished.NotFinished;
@NotFinished(value="Not tested")
public class Jogador  extends Participante implements Cloneable
{
	public static Set<Jogador> allInstances = new HashSet<Jogador>();
	
	private PosicaoJogador posicao;
	private Clube clube;
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Jogador jogador = new Jogador(new CalendarDate(data_nascimento().day(),data_nascimento().month(),data_nascimento().year()),new String(nome()),(Pais)nacionalidade().clone(),posicao(),(Clube)clube.clone());
		Jogador.allInstances.remove(jogador);
		return jogador;
	}
	
	/**********************************************************************
	* Default constructor
	**********************************************************************/
	public Jogador()
	{
		super();
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Parameterized constructor
	* @param data_nascimento the data_nascimento to initialize (inherited)
	* @param nome the nome to initialize (inherited)
	* @param nacionalidade the nacionalidade to initialize (inherited)
	* @param posicao the posicao to initialize
	* @param clube the clube to initialize
	**********************************************************************/
	public Jogador(CalendarDate data_nascimento, String nome, Pais nacionalidade, PosicaoJogador posicao, Clube clube)
	{
		super(data_nascimento, nome, nacionalidade);
		this.posicao = posicao;
		this.clube = clube;
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the posicao of the jogador
	**********************************************************************/
	public PosicaoJogador posicao()
	{
		return posicao;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param posicao the posicao to set
	**********************************************************************/
	public void setPosicao(PosicaoJogador posicao)
	{
		this.posicao = posicao;
	}
	
	/**********************************************************************
	* ONE2MANY getter for Jogador[*] <-> Clube[1]
	* @return the clube of the jogador
	**********************************************************************/
	public Clube clube()
	{
		return clube;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Jogador[*] <-> Clube[1]
	* @param clube the clube to set
	**********************************************************************/
	public void setClube(Clube clube)
	{
		this.clube = clube;
	}
	
	/**********************************************************************
	* MANY2MANY getter for Jogador[*] <-> Participacao[*]
	* @return the participacoes of the plantel
	**********************************************************************/
	public Set<Participacao> participacoes()
	{
		Set<Participacao> result = new HashSet<Participacao>();
		for (Participacao x : Participacao.allInstances)
			if (x.plantel().contains(this))
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* MANY2MANY setter for Jogador[*] <-> Participacao[*]
	* @param participacoes the participacoes to set
	**********************************************************************/
	public void setParticipacoes(Set<Participacao> participacoes)
	{
		for (Participacao x : participacoes)
			x.plantel().add(this);
	}
	
	/**********************************************************************
	* MEMBER2ASSOCIATIVE getter for Jogador[11..*] <-> Membro[*]
	* @return the membro of the jogador
	**********************************************************************/
	public Set<Membro> membro()
	{
		Set<Membro> result = new HashSet<Membro>();
		for (Membro x : Membro.allInstances)
			if (x.jogador()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* MEMBER2ASSOCIATIVE setter for Jogador[11..*] <-> Membro[*]
	* @param membro the membro to set
	**********************************************************************/
	public void setMembro(Set<Membro> membro)
	{
		for (Membro x : membro)
			x.setJogador(this);
	}
	
	/**********************************************************************
	* MEMBER2MEMBER getter for Jogador[11..*] <-> Equipa[*]
	* @return the equipa of the jogador
	**********************************************************************/
	public Set<Equipa> equipa()
	{
		Set<Equipa> result = new HashSet<Equipa>();
		for (Membro x : Membro.allInstances)
			if (x.jogador()  ==  this)
				result.add(x.equipa());
		return result;
	}
	
	/**********************************************************************
	* MEMBER2MEMBER setter for Jogador[11..*] <-> Equipa[*]
	* @param equipa the equipa to set
	**********************************************************************/
	public void setEquipa(Set<Equipa> equipa)
	{
		for (Equipa t : equipa)
			for (Membro x: Membro.allInstances)
				if (x.jogador() == this)
					x.setEquipa(t);
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param nome the nome to set
	* @param data_nascimento the data_nascimento to set
	* @param posicao the posicao to set
	* @param nacionalidade the nacionalidade to set
	* @param clube the clube to set
	**********************************************************************/
	public void inicializa(String nome, CalendarDate data_nascimento, PosicaoJogador posicao, Pais nacionalidade, Clube clube)
	{
		//	TODO
		//	self.nome := nome;
		this.setNome(nome);
		//	 self.data_nascimento := data_nascimento;
		this.setData_nascimento(data_nascimento);
		//	 self.posicao := posicao;
		this.setPosicao(posicao);
		//	 insert (nacionalidade,self) into Pais_Participante;
		this.setNacionalidade(nacionalidade);
		//	 insert (clube,self) into Clube_Jogador;
		this.setClube(clube);
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public Set<Campeonato> obterCampeonatosEmQueOJogadorFazParteDoPlantel()
	{
		//	TODO
		//	return Campeonato.allInstances->reject(c : Campeonato | not c.participacao->collectNested($e : Participacao | $e.plantel)->flatten->exists(j : Jogador | (j = self)))
		Set<Campeonato> campeonatos = (HashSet<Campeonato>) Campeonato.allInstances;
		Iterator<Campeonato> campeonatoIte =campeonatos.iterator();
		while(campeonatoIte.hasNext()){
			boolean remove = true;
			Set<Participacao> campBuffer = campeonatoIte.next().participacao();
			for(Participacao participacao :campBuffer){
				Set<Jogador> plantel = participacao.plantel();
				for(Jogador jogador:plantel){
					if(jogador==this){
						remove = false;
						break;
					}
				}
			}
			if(remove){
				campeonatoIte.remove();
			}
		}
		return null;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public Set<Equipa> obterEquipasEmQueOJogadorNaoAlinha()
	{
		//	TODO
		//	return self.obterCampeonatosEmQueOJogadorFazParteDoPlantel()->collectNested($e : Campeonato | $e.participante)->flatten->reject(p : Pais | (p <> self.nacionalidade))->collectNested($e : Pais | $e.equipa)->flatten->asSet
		HashSet<Equipa> equipas = new HashSet<Equipa>();
		Set<Campeonato> campeonatos = this.obterCampeonatosEmQueOJogadorFazParteDoPlantel();
		for(Campeonato campeonato: campeonatos){
			Set<Pais> participantes = campeonato.participante();
			Iterator<Pais> participantesIte = participantes.iterator();
			while(participantesIte.hasNext()){
				Pais pais = participantesIte.next();
				if(pais!=this.nacionalidade()){
					participantesIte.remove();
				}
			}
			for(Pais pais:participantes){
				Set<Equipa> equipa = pais.equipa();
				for(Equipa eq :equipa){
					equipas.add(eq);
				}
			}
		}
		return equipas;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param t the t to set
	**********************************************************************/
	public int obterNumerosDeCartoes(TipoCartao t)
	{
		//	TODO
		//	return self.membro->collectNested($e : Membro | $e.cartoes)->flatten->select(c : Cartao | (c.tipo = t))->iterate(c : Cartao; res : Integer = 0 | (res + 1))
		Set<Membro> membros = this.membro();
		HashSet<Cartao> cartoes = new HashSet<Cartao>();
		for(Membro m:membros){
			for(Cartao c:m.cartoes()){
				if(c.tipo().equals(t)){
					cartoes.add(c);
				}
			}
		}
		return cartoes.size();
	}
	
	/* (non-Javadoc)
	* @see java.lang.Object#toString()
	*/
	@Override
	/**********************************************************************
	* Object serializer
	**********************************************************************/
	public String toString()
	{
		return "Jogador [posicao=" + posicao + ", clube=" + clube + "]\n";
	}
	
}
